﻿using System;
using FortuneUniverse.Fortune.Algorithms;

namespace FortuneUniverse.Fortune.Dyson
{
  public static class RandomTable
  {
    private const int size = 65536;
    private static VectorLF3[] sphericNormal;
    private static int[] integers;

    private static double Normal(URandom1 rand)
    {
      double num = rand.NextDouble();
      double a = rand.NextDouble() * Math.PI * 2.0;
      return Math.Sqrt(-2.0 * Math.Log(1.0 - num)) * Math.Sin(a);
    }

    public static void Init()
    {
      RandomTable.GenerateSphericNormal();
      RandomTable.GenerateIntegers();
    }

    public static VectorLF3 SphericNormal(ref int seed, double scale)
    {
      ++seed;
      seed &= (int) ushort.MaxValue;
      return new VectorLF3(RandomTable.sphericNormal[seed].x * scale, RandomTable.sphericNormal[seed].y * scale, RandomTable.sphericNormal[seed].z * scale);
    }

    public static int Integer(ref int seed, int maxValue)
    {
      ++seed;
      seed &= (int) ushort.MaxValue;
      return maxValue <= 0 ? 0 : RandomTable.integers[seed] % maxValue;
    }

    public static void GenerateSphericNormal()
    {
      URandom1 rand = new URandom1(1001);
      RandomTable.sphericNormal = new VectorLF3[65536];
      for (int index = 0; index < 65536; ++index)
      {
        double num1;
        double num2;
        double num3;
        double num4;
        double d;
        do
        {
          do
          {
            num1 = rand.NextDouble() * 2.0 - 1.0;
            num2 = rand.NextDouble() * 2.0 - 1.0;
            num3 = rand.NextDouble() * 2.0 - 1.0;
            num4 = RandomTable.Normal(rand);
          }
          while (num4 > 5.0 || num4 < -5.0);
          d = num1 * num1 + num2 * num2 + num3 * num3;
        }
        while (d > 1.0 || d < 1E-06);
        double num5 = num4 / Math.Sqrt(d);
        double x_ = num1 * num5;
        double y_ = num2 * num5;
        double z_ = num3 * num5;
        RandomTable.sphericNormal[index] = new VectorLF3(x_, y_, z_);
      }
    }

    public static void GenerateIntegers()
    {
      URandom1 urandom1 = new URandom1(1002);
      RandomTable.integers = new int[65536];
      for (int index = 0; index < 65536; ++index)
        RandomTable.integers[index] = urandom1.Next();
    }
  }
}
